package com.spark.gaea.data.mybatis.interceptor;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.util.Properties;
import java.util.regex.Pattern;

@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class})})
public class MySQLPaginationInterceptor implements Interceptor {
	private static final Logger LOG;
	private static final String SQL_SELECT_REGEX = "(?is)^\\s*SELECT.*$";
	private static final String SQL_COUNT_REGEX = "(?is)^\\s*SELECT\\s+COUNT\\s*\\(\\s*(?:\\*|\\w+)\\s*\\).*$";

	@Override
	public Object intercept(final Invocation invocation) throws Throwable {
		final StatementHandler target = (StatementHandler) invocation.getTarget();
		final BoundSql boundSql = target.getBoundSql();
		String sql = boundSql.getSql();
		if (StringUtils.isBlank(sql)) {
			return invocation.proceed();
		}
		MySQLPaginationInterceptor.LOG.trace("\u539f\u59cbSQL\u8bed\u53e5 >>>>>> \n" + sql);
		if (sql.matches("(?is)^\\s*SELECT.*$") && !Pattern
				.matches("(?is)^\\s*SELECT\\s+COUNT\\s*\\(\\s*(?:\\*|\\w+)\\s*\\).*$", sql)) {
			final Object obj = FieldUtils.readField(target, "delegate", true);
			final RowBounds rowBounds = (RowBounds) FieldUtils.readField(obj, "rowBounds", true);
			if (rowBounds != null && rowBounds != RowBounds.DEFAULT) {
				sql = sql + " LIMIT " + rowBounds.getLimit() + " OFFSET " + rowBounds.getOffset();
				MySQLPaginationInterceptor.LOG.trace("\u8f6c\u6362\u540eSQL\u8bed\u53e5 >>>>>> \n" + sql);
				FieldUtils.writeField(boundSql, "sql", sql, true);
				FieldUtils.writeField(rowBounds, "offset", 0, true);
				FieldUtils.writeField(rowBounds, "limit", Integer.MAX_VALUE, true);
			}
		}
		return invocation.proceed();
	}

	@Override
	public Object plugin(final Object target) {
		if (target instanceof StatementHandler) {
			return Plugin.wrap(target, this);
		}
		return target;
	}

	@Override
	public void setProperties(final Properties properties) {
	}

	static {
		LOG = LoggerFactory.getLogger(MySQLPaginationInterceptor.class);
	}
}
